package com.gistmap.sideline.service;

import com.gistmap.sideline.entity.Participate;
import com.gistmap.sideline.entity.Partner;
import com.gistmap.sideline.entity.Task;
import com.gistmap.sideline.entity.User;
import com.gistmap.sideline.exception.AppException;
import com.gistmap.sideline.exception.ResourceNotFoundException;
import com.gistmap.sideline.model.TaskStatus;
import com.gistmap.sideline.payload.JoinRequest;
import com.gistmap.sideline.payload.PartnerRequest;
import com.gistmap.sideline.payload.TaskRequest;
import com.gistmap.sideline.payload.TaskResponse;
import com.gistmap.sideline.repository.ParticipateRepository;
import com.gistmap.sideline.repository.PartnerRepository;
import com.gistmap.sideline.repository.TaskRepository;
import com.gistmap.sideline.security.UserPrincipal;
import com.gistmap.sideline.util.ModelMapper;
import com.github.wenhao.jpa.Specifications;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static java.util.stream.Collectors.toList;

@Service
@Transactional
public class TaskService {

    @Autowired
    private TaskRepository taskRepository;
    @Autowired
    private UserService userService;
    @Autowired
    private ParticipateRepository participateRepository;
    @Autowired
    private PartnerRepository partnerRepository;

    public Task get(Long id) {
        return taskRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("Task", "id", id));
    }

    public Task save(Task task) {
        return taskRepository.save(task);
    }

    public void createTask(TaskRequest request) {
        Task task = new Task(request);
        task.setStatus(TaskStatus.ACCESS);
        taskRepository.save(task);
    }

    /**
     * 任务详情
     * @param taskId
     * @return
     */
    public TaskResponse details(Long taskId){
        Task task = get(taskId);
        return ModelMapper.mapTaskToTaskResponse(task,
                participateRepository.findAllByTask(task),
                partnerRepository.findAllByTask(task));
    }

    /**
     * 我发布的任务
     * @param currentUser
     * @return
     */
    public List<TaskResponse> getTasks(UserPrincipal currentUser) {
        Specification<Task> spec = Specifications.<Task>and()
                .eq(true, "createdBy", currentUser.getId())
                .build();
        return taskRepository.findAll(spec)
                .stream()
                .map( task ->
                        ModelMapper.mapTaskToTaskResponse(task,
                                participateRepository.findAllByTask(task),
                                partnerRepository.findAllByTask(task)))
                .collect(toList());
    }

    /**
     * 参与任务
     * @param userPrincipal
     * @param taskId
     * @param request
     */
    public void joinTask(UserPrincipal userPrincipal, Long taskId, JoinRequest request) {
        Task task = get(taskId);
        User user = userService.get(userPrincipal.getId());

        // 检查是否重复报名
        Participate byUserAndTask = participateRepository.findByUserAndTask(user, task);
        if (byUserAndTask != null) {
            throw new AppException("请勿重复报名");
        }

        Participate participate = new Participate();
        participate.setTask(task);
        participate.setUser(user);
        participate.setContent(request.getContent());
        participateRepository.save(participate);
    }

    /**
     * 选中用户
     * @param taskId
     * @param request
     */
    public void choiceUser(Long taskId, PartnerRequest request) {
        Task task = get(taskId);
        User user = userService.get(request.getUserId());

        Partner byUserAndTask = partnerRepository.findByUserAndTask(user, task);
        if (byUserAndTask != null) {
            throw new AppException("请勿重复报名");
        }

        Partner partner = new Partner();
        partner.setTask(task);
        partner.setUser(user);
        task.setStatus(TaskStatus.NOT_ACCESS);
        partnerRepository.save(partner);
    }

}
